#include "core/dev.h"
#include "core/bus.h"

#if (DEVICE_DEBUG > DEVICE_DEBUG_OFF)
static const char *TAG = "DEVICE";
#endif

DEVICE_PUBLIC(static device_t *) device_table[DEVICE_NUM_MAX] = {0};

DEVICE_PUBLIC(void) device_table_info_print(void){
    const int dev_max_num = DEVICE_ARRAY_SIZE(device_table);
    for (int i = 0; i < dev_max_num; i++){
        if (device_table[i] && device_table[i]->compat && device_table[i]->name && device_table[i]->type){
            DEVICE_LOG_INFO(TAG, "dev[%d]:name: %s, compat: %s, type: %d", i, device_table[i]->name,
                            device_table[i]->compat, device_table[i]->type);
        }
    }
}

DEVICE_PUBLIC(int) device_register(device_t *dev, void *bus) {
    if (!dev || !dev->compat || !dev->name) {
        DEVICE_LOG_ERROR(TAG, "device_register param invalid");
        return -1;
    }
    const int dev_max_num = DEVICE_ARRAY_SIZE(device_table);
    for (int i = 0; i < dev_max_num; i++) {
        if (device_table[i] == NULL) {
            if (bus_add_device(bus, dev) != 0) {
                return -2;
            }
            device_table[i] = dev;
            DEVICE_LOG_DEBUG(TAG, "device[%s] register success", dev->name);
            return 0;
        }
    }
    DEVICE_LOG_ERROR(TAG, "device[%s] register error, device table full", dev->name);
    return -3;
}

DEVICE_PUBLIC(int) device_unregister(device_t *dev) {
    if (!dev) {
        DEVICE_LOG_ERROR(TAG, "device_unregister param invalid");
        return -1;
    }
    const int dev_max_num = DEVICE_ARRAY_SIZE(device_table);
    for (int i = 0; i < dev_max_num; i++) {
        if (device_table[i] == dev) {
            if (bus_remove_device(dev->bus, dev) != 0) {
                return -2;
            }
            device_table[i] = NULL;
            DEVICE_LOG_DEBUG(TAG, "device[%s] unregister success", dev->name);
            return 0;
        }
    }
    DEVICE_LOG_ERROR(TAG, "device[%s] unregister error, device not found", dev->name);
    return -3;
}



DEVICE_PUBLIC(device_t *) device_find(const char *name) {
    if (!name) {
        DEVICE_LOG_ERROR(TAG, "device_find param invalid");
        return NULL;
    }
    const int dev_max_num = DEVICE_ARRAY_SIZE(device_table);
    for (int i = 0; i < dev_max_num; i++) {
        if (device_table[i] && device_table[i]->name) {
            if (strcmp(device_table[i]->name, name) == 0) {
                DEVICE_LOG_DEBUG(TAG, "find device[%s] success", device_table[i]->name);
                return device_table[i];
            }
        }
    }
    DEVICE_LOG_ERROR(TAG, "find device[%s] error", name);
    return NULL;
}


DEVICE_PUBLIC(int) device_open(device_t *dev, ...) {
    if (!dev || !dev->ops || !dev->ops->open) {
        return -1;
    }
    va_list args;
    va_start(args, dev);
    int ret = dev->ops->open(dev, args);
    va_end(args);

    return ret;
}

DEVICE_PUBLIC(int) device_close(device_t *dev) {
    return (dev && dev->ops && dev->ops->close) ? dev->ops->close(dev) : -1;
}

DEVICE_PUBLIC(int) device_read(device_t *dev, void *data, uint32_t len) {
    return (dev && dev->ops && dev->ops->read) ? dev->ops->read(dev, data, len) : -1;
}

DEVICE_PUBLIC(int) device_write(device_t *dev, const void *data, uint32_t len) {
    return (dev && dev->ops && dev->ops->write) ? dev->ops->write(dev, data, len) : -1;
}

DEVICE_PUBLIC(int) device_ioctl(device_t *dev, ...) {
    if (!dev || !dev->ops || !dev->ops->ioctl) {
        return -1;
    }

    va_list args;
    va_start(args, dev);
    int ret = dev->ops->ioctl(dev, args);
    va_end(args);

    return ret;
}
